package com.tpshion.cloud.auth.controller;

import com.tpshion.cloud.auth.domain.dto.LoginDto;
import com.tpshion.cloud.auth.domain.dto.MenuDto;
import com.tpshion.cloud.auth.domain.dto.RegisterDto;
import com.tpshion.cloud.auth.domain.entity.Permission;
import com.tpshion.cloud.auth.domain.vo.MenuVo;
import com.tpshion.cloud.auth.service.UserService;
import com.tpshion.cloud.common.support.*;
import com.tpshion.cloud.core.annotation.SessionAware;
import com.tpshion.cloud.core.support.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 认证管理模块
 */
@RestController
public class AuthController {

    private static final Logger log = LoggerFactory.getLogger(AuthController.class);

    @Autowired
    private UserService userService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 用户登录
     * @param loginDto 登录数据
     * @return
     */
    @PostMapping("/login")
    public Result<?> login(@RequestBody @Validated LoginDto loginDto){
        log.info("*** login loginDto:{}",loginDto);
        loginDto.init();
        /**
         * 登录方式：1、账号 2、手机号 3、邮箱
         * 依次判断是否为空，不为空优先使用前面的方式登录
         */
        if(!StringUtils.isEmpty(loginDto.getAccount())){
            //使用账号方式登录
            return userService.loginByAccount(loginDto.getAccount(),loginDto.getPassword());
        }

        if(!StringUtils.isEmpty(loginDto.getPhone())){
            //使用手机号登录
            return userService.loginByPhone(loginDto.getPhone(),loginDto.getPassword());
        }

        if(!StringUtils.isEmpty(loginDto.getEmail())){
            //使用邮箱登录
            return userService.loginByEmail(loginDto.getEmail(),loginDto.getPassword());
        }
        //返回登录数据为空
        return Result.build(ErrorCode.LOGIN_DATA_NULL);
    }

    /**
     * 注册用户
     * @param registerDto
     * @return
     */
    @PostMapping("/register")
    public Result<?> register(@RequestBody @Validated RegisterDto registerDto){
        registerDto.init();
        log.info("*** register registerDto:{}",registerDto);
        Result result = userService.register(registerDto);
        log.info("*** register success result:{}",result);
        return result;
    }

    /**
     * 刷新token过期时间
     * @param refreshDto
     * @return
     */
    @PostMapping("/refresh")
    public Result<?> refresh(@RequestBody @Validated RefreshDto refreshDto){
        log.info("*** refresh token refreshDto:{}",refreshDto);
        String key = Field.TOKEN + "-" + refreshDto.getUserId();
        HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
        String redisToken = hashOperations.get(key, Field.TOKEN);

        Assert.notEmpty(redisToken,ErrorCode.LOGIN_TIMEOUT);
        Assert.isTrue(redisToken.equals(refreshDto.getToken()), ErrorCode.TOKEN_ERROR);

        //重置token过期时间
        redisTemplate.expire(key, Constants.TOKEN_EXPIRE_TIME, TimeUnit.MINUTES);
        return Result.ok();
    }

    /**
     * 用户权限校验
     * @param permission 权限名称
     * @return
     */
    @GetMapping("/permission")
    public Result<?> permission(@RequestParam("permission") String permission,
                                @RequestParam("sysCode") String sysCode,
                                @SessionAware Session session){
        log.info("*** session:{}",session);
        //String userId = session.getUserId();
        //String key = Field.PERMISSION + "-" + userId;
        /**
         * 1、redis查询是否存在权限信息，不存在查询数据库，然后放入缓存
         * 2、redis存在直接判断权限信息
         */
//        HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
//        String permissionJson = hashOperations.get(key, userId);
//        if(!StringUtils.isEmpty(permissionJson)){
//            List<Permission> list = JsonUtil.string2List(permissionJson, Permission.class);
//            for (Permission item : list) {
//                if(item.getSystemCode().equals(sysCode) && item.getName().equals(permission)){
//                    return Result.ok();
//                }
//            }
//        }else{
//            List<Permission> permissionList = userService.findPermission(session.getUserId());
//            hashOperations.put(key, userId, JsonUtil.obj2String(permissionList));
//            redisTemplate.expire(key, Constants.EXPIRE_TIME, TimeUnit.MINUTES);
//            for (Permission item : permissionList) {
//                if(item.getSystemCode().equals(sysCode) && item.getName().equals(permission)){
//                    return Result.ok();
//                }
//            }
//        }

        List<Permission> permissionList = userService.findPermission(session.getUserId());
        for (Permission item : permissionList) {
            if(item.getSysCode().equals(sysCode) && item.getName().equals(permission)){
                return Result.ok();
            }
        }

        return Result.build(ErrorCode.NO_ACCESS);
    }

    /**
     * 退出登录
     */
    @GetMapping("/logout")
    public Result<?> logout(@SessionAware Session session){
        log.info("用户：userId={} 退出登录",session.getUserId());
        Assert.notNull(session, ErrorCode.NO_ACCESS);
        String key = Field.TOKEN + "-" + session.getUserId();
        //清除token缓存
        HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
        hashOperations.delete(key,Field.TOKEN,Field.AUTH_INF);
        return Result.ok("用户已安全退出登录");
    }

    /**
     * 获取用户菜单树
     * @param menuDto
     * @return
     */
    @PostMapping("/menus")
    public Result<?> getMenuList(@RequestBody @Validated MenuDto menuDto){
        menuDto.init();
        log.info("获取用户菜单树 menuDto:{}",menuDto);
        MenuVo menuVo = userService.getMenuTree(menuDto.getUserId(), menuDto.getSysCode());
        return Result.ok(menuVo);
    }

}
